---
title: SecurityService
summary: Contract detail for SecurityService, hosted at the `Security` route.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-22
---

# SecurityService

`SecurityService` implements the external `ISecurityService` contract and is activated over the `Security` route. This page documents every public operation the class exposes.

| Field | Value |
| --- | --- |
| **Service class** | `SAIF.Services.WCF.Services.Security.SecurityService` |
| **Declared contract** | `ISecurityService` — external (`SAIF.Services.WCF.Contracts`, arriving transitively via `SAIF.Framework.Core`) * |
| **Route** | `Security` |
| **Source** | `src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs` |
| **Service attributes** | `[AspNetCompatibilityRequirements(RequirementsMode = Allowed)]`, `[LogErrorBehavior]` |
| **Instancing / concurrency** | WCF defaults — not overridden in source |
| **Binding** | `basicHttpBinding` (default, unnamed — no `<endpoint>` is configured for any of the six routes) |
| **Class-level authorization** | None in code |
| **Error handling** | `[LogErrorBehavior]` installs `ErrorLogErrorHandler`; see [Faults and error pipeline](../faults.md) |
| **Operations** | 10 |
| **Also hosted in** | — |

---

## IsAuthorized

Authorize a user for a role, trying the internal domain first.

| Field | Value |
| --- | --- |
| **Operation name** | `IsAuthorized` |
| **Contract name** | `IsAuthorized` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.IsAuthorized` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-015](../operations/security-isauthorized.md) |

### IsAuthorized input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `userId` | `string` | Yes | — | Account to check; validated non-blank. |
| `role` | `string` | Yes | — | Role/group name to check; validated non-blank. |

### IsAuthorized output message

| Field | Value |
| --- | --- |
| **Return type** | `bool` |
| **Meaning** | Whether `userId` is authorized for `role`. |
| **Empty-result behavior** | Not applicable — always resolves to `true`/`false`. |

### IsAuthorized faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| `SecurityException` (uncategorized) | Not declared | See [OP-015 process detail](../operations/security-isauthorized.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |
| Directory or Oracle/NHibernate exception | Not declared | See [OP-015 process detail](../operations/security-isauthorized.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### IsAuthorized authorization

None in code. Access to `IsAuthorized` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### IsAuthorized side effects

| Aspect | Finding |
| --- | --- |
| Records written | None for this path |
| Downstream calls | Active Directory (`corp.saif.com` and the external LDAP host); ASP.NET `HttpContext.Current.Cache` |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled; populates the shared authorization cache |
| Shared state touched | Reads and, on a cache miss, mutates the process-wide `AuthorizationCacheService` cache and the mutable `ldap_external` field |
| Repeat-call behavior | A cached result short-circuits the directory calls for the TTL window |

---

## IsAuthorized2

Authorize a user for a role with caller-controlled domain order.

| Field | Value |
| --- | --- |
| **Operation name** | `IsAuthorized2` |
| **Contract name** | `IsAuthorized2` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.IsAuthorized2` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-016](../operations/security-isauthorized2.md) |

### IsAuthorized2 input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `userId` | `string` | Yes | — | Account to check; validated non-blank. |
| `role` | `string` | Yes | — | Role/group name to check; validated non-blank. |
| `tryInternalDomainFirst` | `bool` | Yes | — | Whether the internal (`Windows`) domain is checked before the external LDAP domain. |

### IsAuthorized2 output message

| Field | Value |
| --- | --- |
| **Return type** | `bool` |
| **Meaning** | Whether `userId` is authorized for `role`. |
| **Empty-result behavior** | Not applicable — always resolves to `true`/`false`. |

### IsAuthorized2 faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| `SecurityException` (uncategorized) | Not declared | See [OP-016 process detail](../operations/security-isauthorized2.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |
| Directory or Oracle/NHibernate exception | Not declared | See [OP-016 process detail](../operations/security-isauthorized2.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### IsAuthorized2 authorization

None in code. Access to `IsAuthorized2` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### IsAuthorized2 side effects

| Aspect | Finding |
| --- | --- |
| Records written | None for this path |
| Downstream calls | Active Directory (`corp.saif.com` and the external LDAP host); ASP.NET `HttpContext.Current.Cache` |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled; populates the shared authorization cache |
| Shared state touched | Reads and, on a cache miss, mutates the process-wide `AuthorizationCacheService` cache and the mutable `ldap_external` field |
| Repeat-call behavior | A cached result short-circuits the directory calls for the TTL window |

---

## GetUser

Resolve a user across Active Directory, WCIS, ADP, and external-user sources in priority order.

| Field | Value |
| --- | --- |
| **Operation name** | `GetUser` |
| **Contract name** | `GetUser` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetUser` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-017](../operations/security-getuser.md) |

### GetUser input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `userId` | `string` | Yes | — | Account identifier to resolve across internal and external sources. |

### GetUser output message

| Field | Value |
| --- | --- |
| **Return type** | `User` |
| **Meaning** | A `User` projection from whichever source resolved first. |
| **Empty-result behavior** | A `User` with `Exists = false`, an empty contact, and all flags `false` when no source matches. |

### GetUser faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Directory or Oracle/NHibernate exception | Not declared | See [OP-017 process detail](../operations/security-getuser.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetUser authorization

None in code. Access to `GetUser` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetUser side effects

| Aspect | Finding |
| --- | --- |
| Records written | `WcisEmployee`, `Employee`, `ExternalUser`, `ExternalUserType`, `Person` (read only, first match wins) |
| Downstream calls | Active Directory (`SAIF` domain) |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read; same precedence chain re-evaluated each call |

---

## GetSaifUserByUserId

Project an AD principal into a SaifUser, resolving the manager's user id.

| Field | Value |
| --- | --- |
| **Operation name** | `GetSaifUserByUserId` |
| **Contract name** | `GetSaifUserByUserId` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetSaifUserByUserId` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-018](../operations/security-getsaifuserbyuserid.md) |

### GetSaifUserByUserId input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `userId` | `string` | Yes | — | AD account identifier to project as a `SaifUser`. |

### GetSaifUserByUserId output message

| Field | Value |
| --- | --- |
| **Return type** | `SaifUser` |
| **Meaning** | An AD-projected `SaifUser` with department, employee id, manager, job title, desk location, and primary fax. |
| **Empty-result behavior** | `null` when the AD principal is not found. |

### GetSaifUserByUserId faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Directory exception | Not declared | See [OP-018 process detail](../operations/security-getsaifuserbyuserid.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetSaifUserByUserId authorization

None in code. Access to `GetSaifUserByUserId` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetSaifUserByUserId side effects

| Aspect | Finding |
| --- | --- |
| Records written | None |
| Downstream calls | Active Directory (`SAIF` domain, up to two lookups) |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read |

---

## GetSaifUserByEmployeeId

Resolve an ADP employee id to a SaifUser via its AD account.

| Field | Value |
| --- | --- |
| **Operation name** | `GetSaifUserByEmployeeId` |
| **Contract name** | `GetSaifUserByEmployeeId` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetSaifUserByEmployeeId` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-019](../operations/security-getsaifuserbyemployeeid.md) |

### GetSaifUserByEmployeeId input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `employeeId` | `string` | Yes | — | ADP employee identifier to resolve to a SaifUser via the associated AD account. |

### GetSaifUserByEmployeeId output message

| Field | Value |
| --- | --- |
| **Return type** | `SaifUser` |
| **Meaning** | An AD-projected `SaifUser` for the employee's resolved user id, falling back to the ADP projection. |
| **Empty-result behavior** | `null` when no `Employee` row matches `employeeId`. |

### GetSaifUserByEmployeeId faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Directory or Oracle/NHibernate exception | Not declared | See [OP-019 process detail](../operations/security-getsaifuserbyemployeeid.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetSaifUserByEmployeeId authorization

None in code. Access to `GetSaifUserByEmployeeId` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetSaifUserByEmployeeId side effects

| Aspect | Finding |
| --- | --- |
| Records written | `Employee` (read only) |
| Downstream calls | Active Directory (`SAIF` domain) |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read |

---

## GetUserIdForEmployeeId

Resolve an ADP employee id to a plain user id.

| Field | Value |
| --- | --- |
| **Operation name** | `GetUserIdForEmployeeId` |
| **Contract name** | `GetUserIdForEmployeeId` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetUserIdForEmployeeId` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-020](../operations/security-getuseridforemployeeid.md) |

### GetUserIdForEmployeeId input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `employeeId` | `string` | Yes | — | ADP employee identifier whose associated user id is requested. |

### GetUserIdForEmployeeId output message

| Field | Value |
| --- | --- |
| **Return type** | `string` |
| **Meaning** | The `UserId` from the matching `Employee` row. |
| **Empty-result behavior** | `""` when no `Employee` row matches `employeeId`. |

### GetUserIdForEmployeeId faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Oracle/NHibernate exception | Not declared | See [OP-020 process detail](../operations/security-getuseridforemployeeid.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetUserIdForEmployeeId authorization

None in code. Access to `GetUserIdForEmployeeId` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetUserIdForEmployeeId side effects

| Aspect | Finding |
| --- | --- |
| Records written | `Employee` (read only) |
| Downstream calls | None |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read |

---

## GetExternalUser

Resolve an external user and its primary contact.

| Field | Value |
| --- | --- |
| **Operation name** | `GetExternalUser` |
| **Contract name** | `GetExternalUser` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetExternalUser` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-021](../operations/security-getexternaluser.md) |

### GetExternalUser input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `userId` | `string` | Yes | — | External-user identifier to resolve. |

### GetExternalUser output message

| Field | Value |
| --- | --- |
| **Return type** | `ExternalUser` |
| **Meaning** | An `ExternalUser` projection with its primary user type and contact populated. |
| **Empty-result behavior** | `null` when no `ExternalUser` row matches `userId`. |

### GetExternalUser faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Oracle/NHibernate exception | Not declared | See [OP-021 process detail](../operations/security-getexternaluser.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetExternalUser authorization

None in code. Access to `GetExternalUser` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetExternalUser side effects

| Aspect | Finding |
| --- | --- |
| Records written | `ExternalUser`, `ExternalUserType`, `Person`, `Address`, `Phone` (read only) |
| Downstream calls | None |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read |

---

## GetExternalUserByCustomerId

Resolve the most-recent external user for a customer group and user type.

| Field | Value |
| --- | --- |
| **Operation name** | `GetExternalUserByCustomerId` |
| **Contract name** | `GetExternalUserByCustomerId` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetExternalUserByCustomerId` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-022](../operations/security-getexternaluserbycustomerid.md) |

### GetExternalUserByCustomerId input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `customerId` | `string` | Yes | — | Customer group identifier used to locate the most-recently-logged-in matching user. |
| `userType` | `string` | Yes | — | Permitted external user type code(s) used to filter candidates. |

### GetExternalUserByCustomerId output message

| Field | Value |
| --- | --- |
| **Return type** | `ExternalUser` |
| **Meaning** | An `ExternalUser` projection for the most-recently-logged-in matching user. |
| **Empty-result behavior** | `null` when `GetCustomerUserId` resolves no matching user id. |

### GetExternalUserByCustomerId faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Oracle/NHibernate exception | Not declared | See [OP-022 process detail](../operations/security-getexternaluserbycustomerid.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetExternalUserByCustomerId authorization

None in code. Access to `GetExternalUserByCustomerId` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetExternalUserByCustomerId side effects

| Aspect | Finding |
| --- | --- |
| Records written | `ExternalUser`, `ExternalUserType`, `Person`, `Address`, `Phone` (read only) |
| Downstream calls | None |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read; result can change as `LastLogonDate` values change |

---

## GetInjuredWorkerUserByCustomerId

Resolve the most-recent external injured-worker user for a customer group.

| Field | Value |
| --- | --- |
| **Operation name** | `GetInjuredWorkerUserByCustomerId` |
| **Contract name** | `GetInjuredWorkerUserByCustomerId` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetInjuredWorkerUserByCustomerId` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-023](../operations/security-getinjuredworkeruserbycustomerid.md) |

### GetInjuredWorkerUserByCustomerId input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `customerId` | `string` | Yes | — | Customer group identifier used to locate the most-recently-logged-in injured-worker user. |

### GetInjuredWorkerUserByCustomerId output message

| Field | Value |
| --- | --- |
| **Return type** | `ExternalUser` |
| **Meaning** | An `ExternalUser` projection for the most-recently-logged-in matching injured-worker user. |
| **Empty-result behavior** | `null` when `GetCustomerUserId` resolves no matching user id. |

### GetInjuredWorkerUserByCustomerId faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Oracle/NHibernate exception | Not declared | See [OP-023 process detail](../operations/security-getinjuredworkeruserbycustomerid.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetInjuredWorkerUserByCustomerId authorization

None in code. Access to `GetInjuredWorkerUserByCustomerId` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetInjuredWorkerUserByCustomerId side effects

| Aspect | Finding |
| --- | --- |
| Records written | `ExternalUser`, `ExternalUserType`, `Person`, `Address`, `Phone` (read only) |
| Downstream calls | None |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read; result can change as `LastLogonDate` values change |

---

## GetUsersByGroup

Expand group membership from Active Directory, optionally recursive and optionally including disabled accounts.

| Field | Value |
| --- | --- |
| **Operation name** | `GetUsersByGroup` |
| **Contract name** | `GetUsersByGroup` — override, if any, not observable because `ISecurityService` is declared in an external contracts assembly |
| **SOAP action** | Not observable — contract assembly is external |
| **Implementing member** | `SAIF.Services.WCF.Services.Security.SecurityService.GetUsersByGroup` (`src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs`) |
| **Pattern** | Request/response (`IsOneWay` not observable — contract assembly is external) |
| **Binding** | `basicHttpBinding` (default, unnamed) |
| **Authorization** | [None in code](../authentication-authorization.md#authorization-enforcement) |
| **Process** | [OP-024](../operations/security-getusersbygroup.md) |

### GetUsersByGroup input message

| Part | Type | Required | Default | Purpose |
| --- | --- | --- | --- | --- |
| `groupName` | `string` | Yes | — | Directory group to expand. |
| `ldap` | `string` | Yes | — | LDAP path used to open the `DirectoryEntry` for the membership search. |
| `domain` | `string` | No | "saif" | Domain used to resolve `groupName`. |
| `recurse` | `bool` | No | true | Whether nested groups are expanded recursively. |
| `includeDisabled` | `bool` | No | false | Whether disabled accounts are included in the result. |

### GetUsersByGroup output message

| Field | Value |
| --- | --- |
| **Return type** | `string[]` |
| **Meaning** | A de-duplicated, ascending array of `sAMAccountName` values for the group's membership. |
| **Empty-result behavior** | `null` when `groupName` does not resolve to a directory group (not an empty array). |

### GetUsersByGroup faults

| Fault | Declared | Raised when | Surfaced as | Detail crosses the boundary |
| --- | --- | --- | --- | --- |
| Directory exception | Not declared | See [OP-024 process detail](../operations/security-getusersbygroup.md) | Generic SOAP fault produced by The `ErrorLogErrorHandler` installed by `[LogErrorBehavior]` | Yes |

<!-- No `[FaultContract]` is declared on any operation in this host — see Faults and error pipeline. -->

### GetUsersByGroup authorization

None in code. Access to `GetUsersByGroup` rests entirely on the IIS authentication configured for the deployment variant; see [Authentication and authorization](../authentication-authorization.md#authorization-enforcement).

### GetUsersByGroup side effects

| Aspect | Finding |
| --- | --- |
| Records written | None |
| Downstream calls | Active Directory (supplied `domain` and `ldap` path, with an unbounded `SizeLimit = 0` paged search) |
| Files or messages produced | Writes IIS request-detail log lines when `LOG_REQUEST_DETAILS` is enabled |
| Shared state touched | None |
| Repeat-call behavior | Idempotent read; result reflects current directory state |


---

## Coverage checklist

| Public member | Documented section | Pattern |
| --- | --- | --- |
| `bool IsAuthorized(string userId, string role)` | [`IsAuthorized`](#isauthorized) | Request/response |
| `bool IsAuthorized2(string userId, string role, bool tryInternalDomainFirst)` | [`IsAuthorized2`](#isauthorized2) | Request/response |
| `User GetUser(string userId)` | [`GetUser`](#getuser) | Request/response |
| `SaifUser GetSaifUserByUserId(string userId)` | [`GetSaifUserByUserId`](#getsaifuserbyuserid) | Request/response |
| `SaifUser GetSaifUserByEmployeeId(string employeeId)` | [`GetSaifUserByEmployeeId`](#getsaifuserbyemployeeid) | Request/response |
| `string GetUserIdForEmployeeId(string employeeId)` | [`GetUserIdForEmployeeId`](#getuseridforemployeeid) | Request/response |
| `ExternalUser GetExternalUser(string userId)` | [`GetExternalUser`](#getexternaluser) | Request/response |
| `ExternalUser GetExternalUserByCustomerId(string customerId, string userType)` | [`GetExternalUserByCustomerId`](#getexternaluserbycustomerid) | Request/response |
| `ExternalUser GetInjuredWorkerUserByCustomerId(string customerId)` | [`GetInjuredWorkerUserByCustomerId`](#getinjuredworkeruserbycustomerid) | Request/response |
| `string[] GetUsersByGroup(string groupName, string ldap, string domain, bool recurse, bool includeDisabled)` | [`GetUsersByGroup`](#getusersbygroup) | Request/response |

## Related documentation
- [Index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Activation and hosting](../activation-hosting.md)
- [Operations](../operations.md)
- [Faults and error pipeline](../faults.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Dependencies](../dependencies.md)
- [Configuration](../configuration.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Data model](../data-model.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts. Statements marked with `**` could not be confirmed; treat
> as unknown until verified.

## Sources
- src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs
